package wecom

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"time"

	"v2/config"
	"v2/metrics"
	"v2/model"

	"github.com/go-redis/redis/v8"
	"github.com/google/uuid"
)

// WeComAppNotifier 企业微信应用通知器
type WeComAppNotifier struct {
	CorpID      string
	CorpSecret  string
	AgentID     int64
	MsgURL      string
	TokenURL    string
	BaseURL     string // 用于生成操作链接的基本 URL
	token       string
	tokenExpiry time.Time
	redisClient *redis.Client
}

// NewWeComAppNotifier 创建企业微信应用通知器
func NewWeComAppNotifier(corpID, corpSecret string, agentID int64, baseURL string) *WeComAppNotifier {
	// 初始化Redis客户端
	redisClient := redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", config.Global.Redis.Host, config.Global.Redis.Port),
		Password: config.Global.Redis.Password,
		DB:       config.Global.Redis.DB,
	})

	return &WeComAppNotifier{
		CorpID:      corpID,
		CorpSecret:  corpSecret,
		AgentID:     agentID,
		MsgURL:      "https://qyapi.weixin.qq.com/cgi-bin/message/send",
		TokenURL:    "https://qyapi.weixin.qq.com/cgi-bin/gettoken",
		BaseURL:     baseURL,
		redisClient: redisClient,
	}
}

// getToken 获取访问令牌
func (w *WeComAppNotifier) getToken() (string, error) {
	// 如果token还有效，直接返回
	if time.Now().Before(w.tokenExpiry) && w.token != "" {
		return w.token, nil
	}

	resp, err := http.Get(fmt.Sprintf("%s?corpid=%s&corpsecret=%s", w.TokenURL, w.CorpID, w.CorpSecret))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", err
	}

	if code, ok := result["errcode"]; ok && code != float64(0) {
		return "", fmt.Errorf("获取token失败: %v", result)
	}

	token, ok := result["access_token"].(string)
	if !ok {
		return "", fmt.Errorf("token格式错误")
	}

	// 缓存token，提前5分钟过期
	w.token = token
	w.tokenExpiry = time.Now().Add(7195 * time.Second) // 7200-5秒

	return token, nil
}

// GetAccessToken 公开方法获取访问令牌
func (w *WeComAppNotifier) GetAccessToken() (string, error) {
	return w.getToken()
}

// generateAlertToken 生成告警唯一标识
func (w *WeComAppNotifier) generateAlertToken(alertID string) string {
	// 企业微信task_id要求：不能包含特殊字符，建议使用纯数字和字母
	timestamp := time.Now().Unix()
	uuid := uuid.New().String()
	// 去除所有特殊字符，只保留数字和字母
	cleanUUID := ""
	for _, char := range uuid {
		if (char >= '0' && char <= '9') || (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') {
			cleanUUID += string(char)
			if len(cleanUUID) >= 8 {
				break
			}
		}
	}
	return fmt.Sprintf("%d%s", timestamp, cleanUUID)
}

// saveAlertInfo 保存告警信息到Redis
func (w *WeComAppNotifier) saveAlertInfo(token string, alert model.AlertInfo) error {
	if w.redisClient == nil {
		log.Printf("[WeComApp] Redis客户端未初始化")
		return nil
	}

	// 将告警信息序列化为JSON
	alertData, err := json.Marshal(alert)
	if err != nil {
		return fmt.Errorf("序列化告警信息失败: %v", err)
	}

	// 使用前缀避免键冲突
	key := fmt.Sprintf("wecom_alert:%s", token)

	// 保存到Redis，设置24小时过期
	err = w.redisClient.Set(w.redisClient.Context(), key, alertData, 24*time.Hour).Err()
	if err != nil {
		return fmt.Errorf("保存到Redis失败: %v", err)
	}

	log.Printf("[WeComApp] 已保存告警信息到Redis: key=%s, alert=%s", key, alert.RuleName)
	return nil
}

// GetAlertInfo 从 Redis 获取告警信息
func (w *WeComAppNotifier) GetAlertInfo(token string) (*model.AlertInfo, error) {
	if w.redisClient == nil {
		return nil, fmt.Errorf("Redis客户端未初始化")
	}

	key := fmt.Sprintf("wecom_alert:%s", token)

	// 从 Redis 获取数据
	alertData, err := w.redisClient.Get(w.redisClient.Context(), key).Result()
	if err != nil {
		if err == redis.Nil {
			return nil, fmt.Errorf("告警信息不存在或已过期: %s", token)
		}
		return nil, fmt.Errorf("从 Redis 获取数据失败: %v", err)
	}

	// 反序列化
	var alert model.AlertInfo
	if err := json.Unmarshal([]byte(alertData), &alert); err != nil {
		return nil, fmt.Errorf("反序列化告警信息失败: %v", err)
	}

	return &alert, nil
}

// saveResponseCode 保存响应码到Redis（用于卡片更新）
func (w *WeComAppNotifier) saveResponseCode(token, responseCode string) error {
	if w.redisClient == nil {
		log.Printf("[WeComApp] Redis客户端未初始化")
		return nil
	}

	// 使用前缀避免键冲突
	key := fmt.Sprintf("wecom_response_code:%s", token)

	// 保存到Redis，设置24小时过期
	err := w.redisClient.Set(w.redisClient.Context(), key, responseCode, 24*time.Hour).Err()
	if err != nil {
		return fmt.Errorf("保存响应码到Redis失败: %v", err)
	}

	log.Printf("[WeComApp] 已保存响应码到Redis: key=%s, responseCode=%s", key, responseCode)
	return nil
}

// AppendOperationRecord 追加操作记录到Redis
func (w *WeComAppNotifier) AppendOperationRecord(token, record string) error {
	if w.redisClient == nil {
		log.Printf("[WeComApp] Redis客户端未初始化")
		return nil
	}

	// 使用前缀避免键冲突
	key := fmt.Sprintf("wecom_operation_records:%s", token)

	// 获取现有的操作记录
	records, err := w.redisClient.LRange(w.redisClient.Context(), key, 0, -1).Result()
	if err != nil && err != redis.Nil {
		return fmt.Errorf("获取操作记录失败: %v", err)
	}

	// 如果记录已超过10条，删除最旧的记录
	if len(records) >= 10 {
		w.redisClient.LTrim(w.redisClient.Context(), key, 1, -1)
	}

	// 添加新记录到列表末尾
	err = w.redisClient.RPush(w.redisClient.Context(), key, record).Err()
	if err != nil {
		return fmt.Errorf("追加操作记录失败: %v", err)
	}

	// 设置24小时过期
	w.redisClient.Expire(w.redisClient.Context(), key, 24*time.Hour)

	log.Printf("[WeComApp] 已追加操作记录到Redis: key=%s, record=%s", key, record)
	return nil
}

// getOperationRecords 获取操作记录列表
func (w *WeComAppNotifier) getOperationRecords(token string) ([]string, error) {
	if w.redisClient == nil {
		return nil, fmt.Errorf("Redis客户端未初始化")
	}

	key := fmt.Sprintf("wecom_operation_records:%s", token)

	// 从 Redis 获取数据
	records, err := w.redisClient.LRange(w.redisClient.Context(), key, 0, -1).Result()
	if err != nil {
		if err == redis.Nil {
			return []string{}, nil // 没有记录，返回空切片
		}
		return nil, fmt.Errorf("从 Redis 获取操作记录失败: %v", err)
	}

	return records, nil
}

// GetResponseCode 从 Redis 获取响应码
func (w *WeComAppNotifier) GetResponseCode(token string) (string, error) {
	if w.redisClient == nil {
		return "", fmt.Errorf("Redis客户端未初始化")
	}

	key := fmt.Sprintf("wecom_response_code:%s", token)

	// 从 Redis 获取数据
	responseCode, err := w.redisClient.Get(w.redisClient.Context(), key).Result()
	if err != nil {
		if err == redis.Nil {
			return "", fmt.Errorf("响应码不存在或已过期: %s", token)
		}
		return "", fmt.Errorf("从 Redis 获取响应码失败: %v", err)
	}

	return responseCode, nil
}

// GetUserInfo 通过企业微信API获取用户信息
func (w *WeComAppNotifier) GetUserInfo(accessToken, code string) (string, error) {
	// 构建请求URL
	url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s", accessToken, code)

	// 发送GET请求
	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("获取用户信息请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应体失败: %v", err)
	}

	// 解析JSON响应
	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析JSON响应失败: %v", err)
	}

	// 检查是否有错误码
	if errcode, ok := result["errcode"]; ok && errcode != float64(0) {
		return "", fmt.Errorf("企业微信API返回错误: errcode=%v, errmsg=%v", errcode, result["errmsg"])
	}

	// 获取用户ID
	if userid, ok := result["UserId"].(string); ok && userid != "" {
		return userid, nil
	}

	return "", fmt.Errorf("无法从响应中获取用户ID: %s", string(body))
}

// GetUserNameByUID 通过用户ID从企业微信接口获取用户名
func (w *WeComAppNotifier) GetUserNameByUID(accessToken, userID string) (string, error) {
	// 构建请求URL
	url := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s", accessToken, userID)

	// 发送GET请求
	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("获取用户信息请求失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应体失败: %v", err)
	}

	// 解析JSON响应
	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析JSON响应失败: %v", err)
	}

	// 检查是否有错误码
	if errcode, ok := result["errcode"]; ok && errcode != float64(0) {
		return "", fmt.Errorf("企业微信API返回错误: errcode=%v, errmsg=%v", errcode, result["errmsg"])
	}

	// 获取用户名
	if name, ok := result["name"].(string); ok && name != "" {
		return name, nil
	}

	return "", fmt.Errorf("无法从响应中获取用户名: %s", string(body))
}

// GetUserNameByUIDWithCache 通过用户ID获取用户名，优先从Redis缓存
func (w *WeComAppNotifier) GetUserNameByUIDWithCache(accessToken, userID string) (string, error) {
	if w.redisClient == nil {
		// 如果Redis客户端未初始化，直接从API获取
		return w.GetUserNameByUID(accessToken, userID)
	}

	// 构造Redis键
	uidKey := fmt.Sprintf("wecom:uids:%s", userID)

	// 尝试从Redis获取
	username, err := w.redisClient.Get(w.redisClient.Context(), uidKey).Result()
	if err == nil {
		// 缓存命中，直接返回
		return username, nil
	}

	// 缓存未命中，从API获取
	username, err = w.GetUserNameByUID(accessToken, userID)
	if err != nil {
		return "", err
	}

	// 将结果存入Redis，设置24小时过期
	err = w.redisClient.Set(w.redisClient.Context(), uidKey, username, 24*time.Hour).Err()
	if err != nil {
		log.Printf("[WeComApp] 缓存用户名到Redis失败: %v", err)
		// 即使缓存失败，也不影响主流程
	}

	return username, nil
}

// NightingaleClient 夜莺API客户端
type NightingaleClient struct {
	BaseURL  string
	Username string
	Password string
	Client   *http.Client
}

// MuteRule 屏蔽规则（符合夜莺V8 API）
type MuteRule struct {
	GroupID       int            `json:"group_id"`
	Note          string         `json:"note"`
	Severities    []int          `json:"severities"`
	DatasourceIDs []int          `json:"datasource_ids"`
	BTime         int            `json:"btime"`
	ETime         int            `json:"etime"`
	Tags          []TagCondition `json:"tags"`
	Cause         string         `json:"cause"`
	MuteTimeType  int            `json:"mute_time_type"`
	PeriodicMutes []PeriodicMute `json:"periodic_mutes"`
}

// TagCondition 标签条件
type TagCondition struct {
	Func  string `json:"func"`
	Key   string `json:"key"`
	Value string `json:"value"`
}

// PeriodicMute 周期性屏蔽
type PeriodicMute struct {
	EnableSTime      string `json:"enable_stime"`
	EnableETime      string `json:"enable_etime"`
	EnableDaysOfWeek string `json:"enable_days_of_week"`
}

// MuteResponse 屏蔽响应
type MuteResponse struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    struct {
		ID int `json:"id"`
	} `json:"data"`
}

// NewNightingaleClient 创建夜莺客户端
func NewNightingaleClient() *NightingaleClient {
	return &NightingaleClient{
		BaseURL:  config.Global.Nightingale.URL,
		Username: config.Global.Nightingale.Username,
		Password: config.Global.Nightingale.Password,
		Client:   &http.Client{Timeout: 30 * time.Second},
	}
}

// ClaimAlert 认领告警
func (nc *NightingaleClient) ClaimAlert(alertID, userID, notes string) error {
	url := fmt.Sprintf("%s/api/v1/alert-events/%s/claim", nc.BaseURL, alertID)
	payload := map[string]interface{}{
		"user_id": userID,
		"notes":   notes,
	}
	return nc.makeRequest("POST", url, payload)
}

// MuteAlert 屏蔽告警（创建屏蔽规则）
func (nc *NightingaleClient) MuteAlert(alert model.AlertInfo, userID, notes string, durationHours int) error {
	// 构建请求URL
	url := fmt.Sprintf("%s/v1/n9e/alert-mutes", nc.BaseURL)

	// 构建时间
	now := time.Now()
	btime := now.Unix()
	etime := now.Add(time.Duration(durationHours) * time.Hour).Unix()

	// 构建标签条件
	var tagConditions []TagCondition
	for key, value := range alert.TagsMap {
		tagConditions = append(tagConditions, TagCondition{
			Func:  "==",
			Key:   key,
			Value: value,
		})
	}

	// 构建屏蔽规则
	muteRule := MuteRule{
		GroupID:       alert.GroupID,
		Note:          fmt.Sprintf("%s - %s", notes, now.Format("2006-01-02 15:04:05")),
		Severities:    []int{alert.Severity},
		DatasourceIDs: []int{alert.DatasourceID},
		BTime:         int(btime),
		ETime:         int(etime),
		Tags:          tagConditions,
		Cause:         fmt.Sprintf("%s - %s", notes, now.Format("2006-01-02 15:04:05")),
		MuteTimeType:  0,
	}

	// 构建请求体
	reqBody, err := json.Marshal(muteRule)
	if err != nil {
		return fmt.Errorf("序列化屏蔽规则失败: %v", err)
	}

	log.Printf("[Nightingale] 请求夜莺API: %s, 数据: %s", url, string(reqBody))

	// 创建请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqBody))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}

	// 设置Basic认证头
	if nc.Username != "" && nc.Password != "" {
		auth := nc.Username + ":" + nc.Password
		encodedAuth := base64.StdEncoding.EncodeToString([]byte(auth))
		req.Header.Set("Authorization", "Basic "+encodedAuth)
	} else {
		log.Printf("[Nightingale] 警告: 未配置用户名和密码，可能认证失败")
	}

	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	resp, err := nc.Client.Do(req)
	if err != nil {
		return fmt.Errorf("请求夜莺API失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("读取响应失败: %v", err)
	}

	log.Printf("[Nightingale] 夜莺API响应状态码: %d", resp.StatusCode)
	log.Printf("[Nightingale] 夜莺API原始响应: %s", string(body))

	// 检查状态码
	if resp.StatusCode >= 400 {
		return fmt.Errorf("夜莺API返回错误: %d, %s", resp.StatusCode, string(body))
	}

	log.Printf("[Nightingale] 屏蔽规则创建成功")
	return nil
}

// CompleteAlert 完成告警
func (nc *NightingaleClient) CompleteAlert(alertID, userID, notes string) error {
	url := fmt.Sprintf("%s/api/v1/alert-events/%s/resolve", nc.BaseURL, alertID)
	payload := map[string]interface{}{
		"user_id": userID,
		"notes":   notes,
	}
	return nc.makeRequest("POST", url, payload)
}

// UpdateCard 更新卡片内容
func (w *WeComAppNotifier) UpdateCard(token, action, userID string, alert model.AlertInfo) error {
	// 获取访问令牌
	accessToken, err := w.getToken()
	if err != nil {
		return fmt.Errorf("获取访问令牌失败: %v", err)
	}

	// 获取 response_code
	responseCode, err := w.GetResponseCode(token)
	if err != nil {
		log.Printf("[WeComApp] 获取响应码失败: %v", err)
		return fmt.Errorf("获取响应码失败: %v", err)
	}

	// 检查必要参数
	if w.AgentID == 0 {
		return fmt.Errorf("AgentID 不能为空")
	}
	if responseCode == "" {
		return fmt.Errorf("response_code 不能为空")
	}

	log.Printf("[WeComApp] 更新卡片参数检查通过: AgentID=%d, responseCode=%s", w.AgentID, responseCode)

	// 生成操作记录
	currentTime := time.Now().Format("2006-01-02 15:04:05")
	var operationNotes string
	switch action {
	case "claim":
		operationNotes = fmt.Sprintf("用户%s 进行告警认领 [%s]", userID, currentTime)
	case "mute2":
		operationNotes = fmt.Sprintf("用户%s 屏蔽2小时告警 [%s]", userID, currentTime)
	case "mute24":
		operationNotes = fmt.Sprintf("用户%s 屏蔽24小时告警 [%s]", userID, currentTime)
	case "complete":
		operationNotes = fmt.Sprintf("用户%s 进行告警完成 [%s]", userID, currentTime)
	default:
		operationNotes = fmt.Sprintf("用户%s 执行了操作: %s [%s]", userID, action, currentTime)
	}

	// 追加操作记录到Redis
	if err := w.AppendOperationRecord(token, operationNotes); err != nil {
		log.Printf("[WeComApp] 追加操作记录失败: %v", err)
		// 不中断主流程，继续执行卡片更新
	}

	// 获取最新的操作记录（只显示最新的一条）
	records, err := w.getOperationRecords(token)
	if err != nil {
		log.Printf("[WeComApp] 获取操作记录列表失败: %v", err)
		records = []string{} // 出错时使用空列表
	}

	// 构建操作记录文本（只显示最新的一条记录）
	operationHistory := "暂无操作记录"
	if len(records) > 0 {
		// 只显示最新的记录（列表中的最后一条）
		operationHistory = records[len(records)-1]
	}

	// 构建更新后的卡片内容，严格按照企业微信文档要求
	templateCard := map[string]interface{}{
		"card_type": "button_interaction",
		"main_title": map[string]interface{}{
			"title": fmt.Sprintf("%s %s - 已处理", alert.EmojiPrefix(), alert.RuleName),
		},
		"sub_title_text": fmt.Sprintf("集群: %s\n时间: %s\n级别: %s\n当前值: %s\n分组: %s",
			alert.Cluster, alert.FormattedTime, alert.SeverityText, alert.TriggerValue, alert.GroupName),
	}

	// 添加 source（可选但推荐）
	templateCard["source"] = map[string]interface{}{
		"icon_url":   "https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0",
		"desc":       "谛听",
		"desc_color": 0,
	}

	// 添加标签列表（horizontal_content_list）
	horizontalContent := w.buildTagsList(alert.TagsMap)

	// 将操作记录作为额外的horizontal_content添加到标签列表下方
	operationContent := map[string]interface{}{
		"keyname": "操作记录",
		"value":   operationHistory, // 只显示最新的一条记录
		"type":    0,
	}

	// 将操作记录添加到horizontal_content_list
	horizontalContent = append(horizontalContent, operationContent)

	if len(horizontalContent) > 0 {
		templateCard["horizontal_content_list"] = horizontalContent
	}

	// 添加所有按钮
	templateCard["button_list"] = []map[string]interface{}{
		{
			"text":  "认领告警",
			"style": 1,
			"type":  1, // URL跳转类型
			"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=claim", w.BaseURL, token),
			"key":   "claim",
		},
		{
			"text":  "屏蔽2小时",
			"style": 2,
			"type":  1, // URL跳转类型
			"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=mute2", w.BaseURL, token),
			"key":   "mute2",
		},
		{
			"text":  "屏蔽24小时",
			"style": 2,
			"type":  1, // URL跳转类型
			"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=mute24", w.BaseURL, token),
			"key":   "mute24",
		},
		{
			"text":  "告警完成",
			"style": 1,
			"type":  1, // URL跳转类型
			"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=complete", w.BaseURL, token),
			"key":   "complete",
		},
	}

	// 构建完整的更新请求，确保所有必填参数都包含
	// 根据企业微信文档，更新卡片需要包含agentid和response_code等必填参数
	updatedPayload := map[string]interface{}{
		"agentid":       w.AgentID,
		"response_code": responseCode,
		"template_card": templateCard,
		"atall":         uint32(1), // 设置为1，更新整个任务接收人员
	}

	// 发送更新请求
	updateURL := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/message/update_template_card?access_token=%s", accessToken)
	jsonData, err := json.Marshal(updatedPayload)
	if err != nil {
		return fmt.Errorf("JSON序列化失败: %v", err)
	}

	log.Printf("[WeComApp] 更新卡片请求URL: %s", updateURL)
	log.Printf("[WeComApp] 更新卡片请求数据: %s", string(jsonData))

	// 使用http.Client发送请求，确保正确的Content-Type
	client := &http.Client{}
	req, err := http.NewRequest("POST", updateURL, bytes.NewReader(jsonData))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("发送更新请求失败: %v", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	log.Printf("[WeComApp] 更新卡片响应状态码: %d", resp.StatusCode)
	log.Printf("[WeComApp] 更新卡片响应内容: %s", string(body))

	// 检查HTTP状态码
	if resp.StatusCode != 200 {
		return fmt.Errorf("HTTP请求失败，状态码: %d, 响应内容: %s", resp.StatusCode, string(body))
	}

	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return fmt.Errorf("解析响应失败: %v, 响应内容: %s", err, string(body))
	}

	log.Printf("[WeComApp] 更新卡片响应: %v", result)

	// 检查企业微信返回的错误码
	if code, ok := result["errcode"]; ok {
		if code != float64(0) {
			// 获取错误信息
			errorMsg := "未知错误"
			if msg, ok := result["errmsg"]; ok {
				if str, ok := msg.(string); ok {
					errorMsg = str
				}
			}
			return fmt.Errorf("更新卡片失败，错误码: %v, 错误信息: %s, 完整响应: %v", code, errorMsg, result)
		}
	} else {
		return fmt.Errorf("响应中缺少errcode字段，完整响应: %s", string(body))
	}

	// 检查是否有新的 response_code 并保存，用于下一次更新
	if newResponseCode, ok := result["response_code"]; ok {
		if newResponseCodeStr, ok := newResponseCode.(string); ok && newResponseCodeStr != "" {
			// 保存新的 response_code 用于下一次卡片更新
			if err := w.saveResponseCode(token, newResponseCodeStr); err != nil {
				log.Printf("[WeComApp] 保存新的 response_code 失败: %v", err)
			} else {
				log.Printf("[WeComApp] 成功保存新的 response_code: %s", newResponseCodeStr)
			}
		}
	}

	log.Printf("[WeComApp] 卡片更新成功: %s", operationNotes)
	return nil
}

// makeRequest 发送HTTP请求
func (nc *NightingaleClient) makeRequest(method, url string, payload interface{}) error {
	if !config.Global.Nightingale.Enable {
		log.Printf("[Nightingale] 夹莺宵集成未启用，跳过API调用")
		return nil
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("序列化请求数据失败: %v", err)
	}

	req, err := http.NewRequest(method, url, bytes.NewReader(jsonData))
	if err != nil {
		return fmt.Errorf("创建请求失败: %v", err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.SetBasicAuth(nc.Username, nc.Password)

	resp, err := nc.Client.Do(req)
	if err != nil {
		return fmt.Errorf("发送请求失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("夹莺宵API返回错误: %d, %s", resp.StatusCode, string(body))
	}

	log.Printf("[Nightingale] API调用成功: %s %s", method, url)
	return nil
}

// buildTagsList 构建标签列表
func (w *WeComAppNotifier) buildTagsList(tagsMap map[string]string) []map[string]interface{} {
	var tagsList []map[string]interface{}
	for key, value := range tagsMap {
		tagsList = append(tagsList, map[string]interface{}{
			"keyname": key,
			"value":   fmt.Sprintf("`%s`", value), // 使用代码格式
			"type":    0,                          // 添加type字段，避免缺少url字段
		})
	}
	return tagsList
}

// Send 发送交互式卡片消息（企业微信模板卡片）
func (w *WeComAppNotifier) Send(alert model.AlertInfo) error {
	// start := time.Now()
	token, err := w.getToken()
	if err != nil {
		log.Printf("[WeComApp] 获取 token 失败: %v", err)
		metrics.AlertSentCounter.WithLabelValues("wecom_app", "failure").Inc()
		return err
	}

	// 生成唯一的告警标识（用于回调识别）
	alertToken := w.generateAlertToken(alert.ID)

	// 保存告警信息到Redis（用于回调时查找）
	if err := w.saveAlertInfo(alertToken, alert); err != nil {
		log.Printf("[WeComApp] 保存告警信息失败: %v", err)
	}

	// 构建标签列表
	tagsList := w.buildTagsList(alert.TagsMap)

	// 添加操作记录占位符到标签列表下方
	operationContent := map[string]interface{}{
		"keyname": "操作记录",
		"value":   "暂无操作记录",
		"type":    0,
	}

	// 将操作记录添加到horizontal_content_list
	tagsList = append(tagsList, operationContent)

	// 构建交互式模板卡片
	payload := map[string]interface{}{
		"touser":  "@all", // 可配置为特定用户
		"msgtype": "template_card",
		"agentid": w.AgentID,
		"template_card": map[string]interface{}{
			"card_type": "button_interaction",
			"task_id":   alertToken, // 使用alertToken作为唯一task_id
			"source": map[string]interface{}{
				"icon_url":   "https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0",
				"desc":       "谛听",
				"desc_color": 0,
			},
			"main_title": map[string]interface{}{
				"title": fmt.Sprintf("%s %s", alert.EmojiPrefix(), alert.RuleName),
			},
			"sub_title_text": fmt.Sprintf("集群: %s\n时间: %s\n级别: %s\n当前值: %s\n分组: %s", alert.Cluster, alert.FormattedTime, alert.SeverityText, alert.TriggerValue, alert.GroupName),
			"quote_area": map[string]interface{}{
				"type":       0, // 0=无点击事件，避免缺少url字段
				"title":      "## 触发表达式",
				"quote_text": fmt.Sprintf("```\n%s\n```", alert.PromQl), // 使用代码块格式
			},
			"horizontal_content_list": tagsList, // 使用包含操作记录的标签列表
			"button_list": []map[string]interface{}{
				{
					"text":  "认领告警",
					"style": 1, // 主要按钮
					"type":  1, // URL跳转类型
					"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=claim", w.BaseURL, alertToken),
				},
				{
					"text":  "屏蔽2小时",
					"style": 2, // 次要按钮
					"type":  1, // URL跳转类型
					"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=mute2", w.BaseURL, alertToken),
				},
				{
					"text":  "屏蔽24小时",
					"style": 2, // 次要按钮
					"type":  1, // URL跳转类型
					"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=mute24", w.BaseURL, alertToken),
				},
				{
					"text":  "告警完成",
					"style": 1, // 主要按钮
					"type":  1, // URL跳转类型
					"url":   fmt.Sprintf("%s/alert/wecom/callback?token=%s&action=complete", w.BaseURL, alertToken),
				},
			},
		},
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		log.Printf("[WeComApp] JSON 序列化失败: %v", err)
		metrics.AlertSentCounter.WithLabelValues("wecom_app", "failure").Inc()
		return err
	}

	log.Printf("[WeComApp] 发送请求URL: %s?access_token=%s", w.MsgURL, token)
	log.Printf("[WeComApp] 发送请求数据: %s", string(jsonData))

	resp, err := http.Post(
		fmt.Sprintf("%s?access_token=%s", w.MsgURL, token),
		"application/json",
		bytes.NewReader(jsonData),
	)
	if err != nil {
		log.Printf("[WeComApp] 请求失败: %v", err)
		metrics.AlertSentCounter.WithLabelValues("wecom_app", "failure").Inc()
		return err
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	log.Printf("[WeComApp] 企业微信响应: %s", string(body))

	var result map[string]interface{}
	json.Unmarshal(body, &result)

	if code, ok := result["errcode"]; ok && code != float64(0) {
		log.Printf("[WeComApp] 返回错误: %v", result)
		metrics.AlertSentCounter.WithLabelValues("wecom_app", "failure").Inc()
		return nil
	}

	// 保存 response_code 用于卡片更新
	if responseCode, ok := result["response_code"]; ok {
		if responseCodeStr, ok := responseCode.(string); ok {
			w.saveResponseCode(alertToken, responseCodeStr)
			log.Printf("[WeComApp] 保存 response_code: %s", responseCodeStr)
		} else {
			log.Printf("[WeComApp] 警告: response_code 不是字符串类型: %T", responseCode)
		}
	} else {
		log.Printf("[WeComApp] 警告: 未返回 response_code，无法更新卡片。完整响应: %v", result)
	}

	metrics.AlertSentCounter.WithLabelValues("wecom_app", "success").Inc()
	// metrics.AlertSendDuration.WithLabelValues("wecom_app").Observe(time.Since(start).Seconds())
	log.Printf("[WeComApp] 已发送交互式卡片: %s", alert.RuleName)
	return nil
}
